﻿#region License Info
//Component of Cronos Package, http://www.codeplex.com/cronos
//Copyright (C) 2009 Anthony Brockwell

//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or (at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#endregion


using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using ABMath.ModelFramework.Data;

namespace ExtraControlLibrary.DirectedGraphs
{
    public partial class NodeButton : Button
    {
        public DirectedGraph.NodeInfo NodeInfo { get; set; }

        public NodeButton(DirectedGraph.NodeInfo nodeInfo)
        {
            NodeInfo = nodeInfo;
            InitializeComponent();
        }

        // here we override label setting and getting to translate a single ampersand into a double ampersand and vice versa
        public override string Text
        {
            get
            {
                return base.Text;
            }
            set
            {
                var sepd = value.Split('&');
                var sb = new StringBuilder(64);
                sb.Append(sepd[0]);
                for (int i = 1; i < sepd.Length; ++i)
                    sb.AppendFormat("&&{0}", sepd[i]);
                base.Text = sb.ToString();
            }
        }

        public void SetCoordinate(double[] newPosition)
        {
            NodeInfo.coordinate = newPosition;
        }

        public Point GetEdgeInDirection(double Xdir, double Ydir)
        {
            var center = new Point(Left + Width/2, Top + Height/2);
            Rectangle rect = Bounds;
            rect.Inflate(3, 3);
            
            // (1) find intersection with top or bottom line
            Point? topIntersection = null;
            if (Ydir < 0) // it's with top
                topIntersection = new Point(
                    (int)(center.X - (center.Y - rect.Top) * Xdir / Ydir),
                       rect.Top
                    );
            else if (Ydir > 0) // it's with bottom
                topIntersection = new Point(
                    (int)(center.X + (center.Y - rect.Top) * Xdir / Ydir),
                       rect.Bottom
                    );

            Point? leftIntersection = null;
            if (Xdir < 0) // it's with left
                leftIntersection = new Point(
                    rect.Left, 
                    (int) (center.Y - (center.X - rect.Left)*Ydir/Xdir)
                    );
            else if (Xdir > 0) // it's with right
            {
                leftIntersection = new Point(
                    rect.Right,
                    (int)(center.Y + (center.X - rect.Left) * Ydir / Xdir)
                    );
            }

            Point retval;
            if (topIntersection == null)
                if (leftIntersection == null)
                    throw new ArgumentException("Cannot have both Components of direction equal to zero.");
                else
                    retval = (Point) leftIntersection;
            else
            {
                if (leftIntersection == null)
                    retval = (Point) topIntersection;
                else
                {
                    // find best of the two points
                    double d1 = PointDistance((Point)leftIntersection, center);
                    double d2 = PointDistance((Point) topIntersection, center);
                    if (d1 < d2)
                        retval = (Point) leftIntersection;
                    else
                        retval = (Point) topIntersection;
                }
            }
            return retval;
        }

        private double PointDistance(Point p1, Point p2)
        {
            return Math.Sqrt((p1.X - p2.X)*(p1.X - p2.X) + (p1.Y - p2.Y)*(p1.Y - p2.Y));
        }

        protected override void OnClick(EventArgs e)
        {
            base.OnClick(e);

            // it's a select event
            var nea = new NodeEventArgs();
            nea.nodeList = new List<DirectedGraph.NodeInfo>();

            var dagViewer = Parent as DirectedGraphViewer;
            if (dagViewer == null)
                return;

            dagViewer.SelectedNode = NodeInfo;
            nea.nodeList.Add(NodeInfo);
            dagViewer.OnNodeSelectEvent(nea);
            Focus();
        }

        private DateTime lastMouseDownTime;

        protected override void OnMouseDown(MouseEventArgs mevent)
        {
            lastMouseDownTime = DateTime.Now;
            if (mevent.Button == MouseButtons.Right)
            {
                // then we are anchoring
                var dagViewer = Parent as DirectedGraphViewer;
                dagViewer.SetAnchor(NodeInfo, mevent.X, mevent.Y);
            }

            base.OnMouseDown(mevent);
        }

        protected override void OnMouseUp(MouseEventArgs mevent)
        {
            lastMouseDownTime = DateTime.Now;
            if (mevent.Button == MouseButtons.Right)
            {
                // then we are anchoring
                var dagViewer = Parent as DirectedGraphViewer;
                dagViewer.EndAnchor(NodeInfo, mevent.X + Left, mevent.Y + Top);
            }

            base.OnMouseUp(mevent);
        }

        protected override void OnMouseMove(MouseEventArgs mevent)
        {
            base.OnMouseMove(mevent);
            if ((MouseButtons & MouseButtons.Left) == MouseButtons.Left)
            {
                var delay = DateTime.Now - lastMouseDownTime;
                if (delay.Ticks > new TimeSpan(0,0,0,0,250).Ticks)
                    DoDragDrop(this, DragDropEffects.Move);
            }
        }

        protected override void OnKeyDown(KeyEventArgs kevent)
        {
            base.OnKeyDown(kevent);
            var dag = Parent as DirectedGraphViewer;
            dag.DirectedGraphViewer_KeyDown(this, kevent);
        }

        protected override void OnMouseWheel(MouseEventArgs e)
        {
            var dag = Parent as DirectedGraphViewer;
            dag.DirectedGraphViewer_MouseWheel(this, e);
        }
    }
}
